#!/usr/bin/env python

import sys
import os
import shlex
import commands
import logging

from optparse import OptionParser

class Module:
    def __init__(self,name,url,version):
        self.name=name
        self.url=url
        self.version=version

    def __repr__(self):
        return "Module(name=%s, url=%s, version=%s)"%(self.name, self.url, self.version)
    
def buildModuleList(moduledef):
    inf=open(moduledef,"r")
    mstr=inf.read().split("\n")
    inf.close()

    modulelist={}
    
    for imstr in mstr:
        spimstr=shlex.split(imstr.strip())
        if len(spimstr)>0 and imstr.strip()[0]!="#":
            modulelist[spimstr[0]]=Module(name=spimstr[0],url=spimstr[1],version=spimstr[2])

    logging.debug(str(modulelist))
    return modulelist

def doCheckin(options):
    modulelist=buildModuleList(options.moduledef)

    for ikey in modulelist.keys():
        imodule=modulelist[ikey]

        targetdir=options.moduledir+"/"+imodule.name

        cmdstr="svn ci %s %s -m \"%s\""%(targetdir,options.svnopts,options.notes)
        logging.debug("Running command %s"%cmdstr)

        (status,output)=commands.getstatusoutput(cmdstr)

        if status!=0:
            raise RuntimeError("Can't do checkout %s, error message: %s"%(cmdstr,output))
        
        logging.debug("output=%s"%(output))

def doStatus(options):
    modulelist=buildModuleList(options.moduledef)

    for ikey in modulelist.keys():
        imodule=modulelist[ikey]

        targetdir=options.moduledir+"/"+imodule.name

        cmdstr="svn status %s %s"%(targetdir,options.svnopts)
        logging.debug("Running command %s"%cmdstr)

        (status,output)=commands.getstatusoutput(cmdstr)

        if status!=0:
            raise RuntimeError("Can't do checkout %s, error message: %s"%(cmdstr,output))
        
        logging.info("Status of %s:\n%s"%(imodule.name,output))

        
def doUpdate(options):
    modulelist=buildModuleList(options.moduledef)

    modulefilestr=""
    
    for ikey in modulelist.keys():
        imodule=modulelist[ikey]

        #Build Modules.pp file
        modulefilestr=modulefilestr+"import \"%s\"\n"%imodule.name
        
        #Checkout/update module
        targetdir=options.moduledir+"/"+imodule.name

        if not os.path.exists(targetdir+"/.svn"):

            #Check it out
            logging.info("Checking out Module %s..."%imodule.name)
            
            if imodule.version=="trunk":
                svnurl=imodule.url+"/trunk"
            else:
                svnurl=imodule.url+"/tags/"+version
        
            cmdstr="svn co %s %s %s"%(svnurl, targetdir,options.svnopts)
            logging.debug("running command %s"%cmdstr)
            
            (status,output)=commands.getstatusoutput(cmdstr)
            
            if status!=0:
                raise RuntimeError("Can't do checkout %s, error message: %s"%(cmdstr,output))
            logging.debug("commandoutput=%s"%output)
        else:
            #Update it
            logging.info("Updating Module %s..."%imodule.name)

            cmdstr="svn update %s %s"%(targetdir,options.svnopts)

            (status,output)=commands.getstatusoutput(cmdstr)
            
            logging.debug("running command %s"%cmdstr)
            if status!=0:
                raise RuntimeError("Can't do update %s, error message: %s"%(cmdstr,output))
            logging.debug("commandoutput=%s"%output)

    ouf=open(options.modulesppfile,"w")
    ouf.write(modulefilestr)
    ouf.close()

if __name__ == "__main__":

    LEVELS = {'debug': logging.DEBUG,
              'info': logging.INFO,
              'warning': logging.WARNING,
              'error': logging.ERROR,
              'critical': logging.CRITICAL,
              'notset':logging.NOTSET}

    parser = OptionParser()

    parser.add_option("-a", "--action",type="string",dest="action",help="action to do, can be ci/checkin, co/checkout, or update",metavar="ACTION", default="")
    parser.add_option("-d", "--moduledef",type="string",dest="moduledef",help="modules.def file to be used",metavar="MODULEDEF",default="")
    parser.add_option("-m", "--moduledir",type="string",dest="moduledir",help="modules.def file to be used",metavar="MODULEDIR",default="")
    parser.add_option("--modulesppfile",type="string",dest="modulesppfile",help="path to the manifests/modules.pp file",metavar="MODULESdotPP",default="")
    parser.add_option("--notes",type="string",dest="notes",help="notes to use when checking-in changes",metavar="NOTES",default="")
    parser.add_option("--svnopts",type="string",dest="svnopts",help="additional svn options",metavar="SVNOPTS",default="")
    parser.add_option("--loglevel",type="string",dest="loglevel",help="log level debug/info/warning/error/critical, default=notset",metavar="LOGLEVEL",default="notset")

    (options, args) = parser.parse_args()

    logging.basicConfig(level=LEVELS[options.loglevel])

    if options.action=="" or options.moduledef=="" or options.moduledir=="":
        logging.critical("always need to provide --action --moduledef and --moduledir, use -h to see help")
        sys.exit(1)

    if options.action=="ci" or options.action=="checkin":
        if options.notes=="":
            logging.critical("need to provide --notes when checking-in")
            sys.exit(1)
        doCheckin(options)
        
    elif options.action=="co" or options.action=="checkout" or options.action=="update":
        if options.modulesppfile=="":
            logging.critical("need to provide --modulesppfile when checking-out")
            sys.exit(1)
        doUpdate(options)

    elif options.action=="status":
        doStatus(options)
        
    sys.exit(0)
